﻿
#region 作者和版权
/*************************************************************************************
* CLR 版本: 4.0.30319.42000
* 类 名 称: HttpServer
* 机器名称: SUNTIA-QL
* 命名空间: ServerFramework.Net.Http
* 文 件 名: HttpServer
* 创建时间: 2015/9/23 9:31:52
* 作 者: 乔龙 Qiaolong
* 版 权: HttpServer说明：本代码版权归乔龙所有，使用时必须带上乔龙网站地址 All Rights Reserved (C) 2015 - 2013
* 签 名: To be or not, it is not a problem !
* 网 站: http://www.suntia.net
* 邮 箱: qiaolong306@qq.com 
* 唯一标识： f180d385-82cf-4c19-8520-5e085e0ffc7e 
*
* 登录用户: simida
* 所 属 域: SUNTIA-QL

* 创建年份: 2015
* 修改时间:
* 修 改 人:
* 
************************************************************************************/
#endregion

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using ServerFramework.Tools;


namespace ServerFramework.Net.Http
{
    /// <summary>
    /// 一个简单http服务
    /// </summary>
    public class HttpServer:IDisposable
    {
        /// <summary>
        /// http 监听
        /// </summary>
        private HttpListener _http;

        /// <summary>
        ///所有的http route
        /// </summary>
        private Dictionary<string, IHttpRoute> _routes = new Dictionary<string, IHttpRoute>();

        /// <summary>
        /// 当前监听的http url
        /// </summary>
        private string _httpUrl;

        /// <summary>
        /// 当发生非法访问时，返回的错信息
        /// </summary>
        private const string _httpErrorInfo = @"404";

        /// <summary>
        /// 增加一个路由器
        /// </summary>
        /// <param name="route">路由器名</param>
        public void AddRoute(string path,IHttpRoute route)
        {
            if (!_routes.ContainsKey(path))
            {
                _routes.Add(path,route);
            }
        }

        /// <summary>
        /// 启动http服务器
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public bool StartServer(string url)
        {
            _http = new HttpListener();
            try
            {
                _httpUrl = url;
                _http.Prefixes.Add(url);
                _http.Start();
                Log.WriteLog(ELogLevel.LOG_INFO, "start [" + url.ToString() +"]");
                //这里我们启动cpu数+1 个异步，防止多人同时访问时阻塞
                for (int i = 0; i < Environment.ProcessorCount+1; ++i)
                {
                    IAsyncResult result = _http.BeginGetContext(OnRequest, null);
                }
                return true;
            }
            catch (Exception e)
            {
                Log.WriteLog(ELogLevel.LOG_ERROR, e);
                return false;
            }
        }

        /// <summary>
        /// 当请求发生时
        /// </summary>
        /// <param name="result">异步返回结果</param>
        private void OnRequest(IAsyncResult result)
        {
            try
            {
                var context = _http.EndGetContext(result);
                ProcessRequest(context);
                result = _http.BeginGetContext(OnRequest, null);
            }
            catch (Exception)
            {
            }
        }

        /// <summary>
        /// 处理请求
        /// </summary>
        /// <param name="result">请求内容</param>
        private void ProcessRequest(HttpListenerContext context)
        {
            HttpListenerRequest request = context.Request;
            string RemoteAddress = request.RemoteEndPoint.ToString();
            HttpListenerResponse response = context.Response;
            string routeString = request.RawUrl;
            int index = request.RawUrl.IndexOf('?');
            if (index != -1)
            {
                routeString = request.RawUrl.Remove(index, request.RawUrl.Length - index);
            }
            if (_routes.ContainsKey(routeString))
            {
                try
                {
                    DateTime start = DateTime.Now;
                    bool ret = _routes[routeString].Process(request, response);
                    DateTime end = DateTime.Now;
                    if ((end - start).TotalMilliseconds > 500)
                    {
                        Log.WriteLog(ELogLevel.LOG_INFO, "long loop : take time = " + (end - start).TotalMilliseconds + "ms,route =" + routeString);
                    }
                    if (!ret)
                    {
                        byte[] responseBytes = Encoding.UTF8.GetBytes(_httpErrorInfo);
                        response.Close(responseBytes, true);
                    }
                }
                catch (Exception e)
                {
                    byte[] responseBytes = Encoding.UTF8.GetBytes(_httpErrorInfo);
                    Log.WriteLog(ELogLevel.LOG_ERROR, e.Message);
                    Log.WriteLog(ELogLevel.LOG_ERROR, "illegality address = " + RemoteAddress);
                    response.Close(responseBytes, true);
                }

            }
            else
            {
                Log.WriteLog(ELogLevel.LOG_INFO, "not find route = " + routeString);
                Log.WriteLog(ELogLevel.LOG_ERROR, "illegality address = " + RemoteAddress);
                byte[] responseBytes = Encoding.UTF8.GetBytes(_httpErrorInfo);
                response.Close(responseBytes, true);
            }
        }



        public void Dispose()
        {
            Close();
        }

        /// <summary>
        /// 关闭http 监听
        /// </summary>
        public void Close()
        {
            if (_http != null)
            {
                _http.Close();
                _http = null;
            }
        }
    }
}


